﻿using System;
using System.Collections.Generic;
using Microsoft.Practices.Unity;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using SharedGenomics.Workbench.Core;
using SharedGenomics.Workbench.Presenters;
using SharedGenomics.Workbench.Views;
using SharedGenomics.Annotations;
using SharedGenomics.Workbench.Services;
using SharedGenomics.Workbench.Tests.TestObjects;

namespace SharedGenomics.Workbench.Tests.Core
{
    [TestClass]
    public class AnnotationWrapperInitialisationTests
    {
        private Rhino.Mocks.MockRepository mocks;
        private IUnityContainer container;
        private PresenterInitialisationContext context;
        private AnnotationWrapperPresenterInitialisationStage stage;

        [TestInitialize]
        public void Setup()
        {
            this.mocks = new Rhino.Mocks.MockRepository();
            IAnnotationWrapperView wrapperView = this.mocks.Stub<IAnnotationWrapperView>();
            IAnnotationSessionManager asm = this.mocks.Stub<IAnnotationSessionManager>();

            this.container = new UnityContainer();
            this.container.RegisterInstance<IAnnotationWrapperView>(wrapperView);
            this.container.RegisterInstance<IAnnotationSessionManager>(asm);
            this.container.RegisterInstance<IAnnotationNotifier>(this.mocks.Stub<IAnnotationNotifier>());
            this.container.RegisterInstance<IBackgroundExecutor>(this.mocks.Stub<IBackgroundExecutor>());
            this.container.RegisterInstance<IEventBroker>(this.mocks.Stub<IEventBroker>());

            this.context = new PresenterInitialisationContext();
            this.context.Container = this.container;

            this.stage = new AnnotationWrapperPresenterInitialisationStage();
        }

        [TestMethod]
        public void ShouldWrapPresenter()
        {
            this.stage.WrapPresenter<StubPresenter>();
            var innerPresenter = new StubPresenter();
            this.context.Current = innerPresenter;
            this.context.PresenterType = typeof(StubPresenter);

            this.stage.Initialise(context);

            //current should be a wrapper presenter and the wrapped presenter should be of type stub presenter
            Assert.IsInstanceOfType(context.Current, typeof(AnnotationWrapperPresenter));
            Assert.AreSame(innerPresenter, ((AnnotationWrapperPresenter)context.Current).WrappedPresenter);
        }

        [TestMethod]
        public void ShouldNotWrapPresenter()
        {
            var innerPresenter = new StubPresenter();
            this.context.Current = innerPresenter;
            this.context.PresenterType = typeof(StubPresenter);

            this.stage.Initialise(context);

            //since no presenter types to wrap have been added to the stage, it should not wrap the presenter in the context
            Assert.IsInstanceOfType(context.Current, typeof(StubPresenter));
        }

        [TestMethod]
        public void ShouldNotWrapPresenterIfCurrentNull()
        {
            this.stage.Initialise(context);
            Assert.IsNull(context.Current);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void ShouldThrowIfContextNull()
        {
            this.stage.Initialise(null);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void ShouldThrowIfContainerNull()
        {
            this.context.Container = null;
            this.stage.Initialise(this.context);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void ShouldThrowIfTypeNull()
        {
            this.stage.WrapPresenter(null);
        }

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void ShouldThrowIfTypeNotPresenterType()
        {
            this.stage.WrapPresenter(typeof(string));
        }
    }
}
